package com.jacken.mars.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jacken.mars.commons.constant.CommonConstants;
import com.jacken.mars.entity.base.BasePageRequest;
import com.jacken.mars.entity.req.SysMenuReq;
import com.jacken.mars.entity.vo.SysMenuListVo;
import com.jacken.mars.entity.vo.SysUserMenuVo;
import com.jacken.mars.commons.exception.WorkException;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.jacken.mars.service.SysMenuService;
import com.jacken.mars.mapper.SysMenuMapper;
import com.jacken.mars.entity.SysMenu;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;


/**
 * 实现层
 *
 * @Author wq
 * @Date 2020-12-15
 **/
@Service
@Transactional(rollbackFor = Exception.class)
public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu> implements SysMenuService {

    @Override
    public IPage<SysMenu> page(BasePageRequest query) {
        IPage<SysMenu> page = new Page<>(query.getPageNumber(), query.getPageSize());
        return baseMapper.findByQuery(page, query);
    }

    @Override
    public List<String> findPermission(Integer roleId) {
        return baseMapper.selectPermissions(roleId);
    }

    @Override
    public void add(SysMenuReq req) {
        SysMenu sysMenu = new SysMenu();
        BeanUtil.copyProperties(req, sysMenu);
        sysMenu.setCreateTime(new Date());
        sysMenu.setUpdateTime(new Date());
        save(sysMenu);
    }

    @Override
    public void delete(Integer id) {
        //查询该菜单下面是否还有菜单
        SysMenu sysMenu = getById(id);
        if (Objects.nonNull(sysMenu)) {
            if (sysMenu.getParentId().equals(CommonConstants.ZERO)) {
                //查询该父级菜单下还有没有子菜单
                List<SysMenu> list = baseMapper.selectChildren(id);
                if (list.size() > CommonConstants.ZERO) {
                    throw new WorkException("该菜单下还有子菜单不能删除");
                } else {
                    baseMapper.deleteById(id);
                }
            } else {
                baseMapper.deleteById(id);
            }
        }
    }

    @Override
    public void updateMenu(SysMenuReq req) {
        SysMenu sysMenu = getById(req.getId());
        if (Objects.isNull(sysMenu)) {
            throw new WorkException("数据不存在");
        }
        SysMenu menu = new SysMenu();
        BeanUtil.copyProperties(req, menu);
        updateById(menu);
    }

    @Override
    public List<SysMenuListVo> getList(Integer id, String menuName) {
        LambdaQueryWrapper<SysMenu> wrapper = new LambdaQueryWrapper<>();
        if (Objects.nonNull(id)) {
            wrapper.eq(SysMenu::getId, id);
        }
        if (StringUtils.isNotEmpty(menuName)) {
            wrapper.like(SysMenu::getTitle, menuName);
        }
        wrapper.orderByDesc(SysMenu::getSort);
        List<SysMenu> menuList = list(wrapper);
        return buildMenus(menuList, 0, id, menuName);
    }

    @Override
    public List<SysUserMenuVo> findMenuRole(Integer roleId) {
        //查询所有菜单列表
        List<SysMenu> menuList = baseMapper.selectMenusRoleId(roleId);
        //递归构建菜单属性结构
        return recursionMenu(0, menuList);
    }

    @Override
    public boolean isExistChildren(Integer id) {

        SysMenu adminMenu = getOne(new QueryWrapper<SysMenu>()
                .eq("parent_id", id)
                .last("limit 1"));
        return adminMenu != null;
    }

    /**
     * 递归遍历菜单集合
     *
     * @param parentId 父级ID
     * @param menuList 菜单集合
     * @return List<SysUserMenuVo>
     */
    private List<SysUserMenuVo> recursionMenu(Integer parentId, List<SysMenu> menuList) {
        List<SysUserMenuVo> sysUserMenuVos = new ArrayList<>();
        //查询父级菜单  遍历所有菜单
        for (SysMenu sysMenu : menuList) {
            if (sysMenu.getParentId().equals(parentId)) {
                SysUserMenuVo sysUserMenuVo = new SysUserMenuVo();
                sysUserMenuVo.setIcon(sysMenu.getIcon());
                sysUserMenuVo.setId(sysMenu.getId());
                sysUserMenuVo.setPath(sysMenu.getPath());
                sysUserMenuVo.setTitle(sysMenu.getTitle());
                sysUserMenuVos.add(sysUserMenuVo);
            }
        }
        //遍历父级菜单
        for (SysUserMenuVo sysUserMenuVo : sysUserMenuVos) {
            List<SysUserMenuVo> chirdenList = recursionMenu(sysUserMenuVo.getId(), menuList);
            if (chirdenList.size() > CommonConstants.ZERO) {
                sysUserMenuVo.setChildren(chirdenList);
            }
        }
        return sysUserMenuVos;
    }


    /**
     * 递归菜单集合
     *
     * @param parentId 父级ID
     * @param menus    菜单集合
     * @return 树形结构的菜单
     */
    private List<SysMenuListVo> buildMenus(List<SysMenu> menus, Integer parentId, Integer id, String menuName) {
        //搜索条件
        if (Objects.nonNull(id) || StringUtils.isNotEmpty(menuName)) {
            for (SysMenu menu : menus) {
                if (menu.getParentId().equals(parentId)) {
                    return menus.stream().map(x -> getSysMenuListVo(parentId, x)).collect(Collectors.toList());
                }
            }
            return menus.stream().filter(sysMenu -> !sysMenu.getParentId().equals(parentId)).
                    map(x -> getSysMenuListVo(parentId, x)).collect(Collectors.toList());
        }
        //遍历所有菜单 找出所有父级菜单
        List<SysMenuListVo> list = menus.stream().
                filter(sysMenu -> sysMenu.getParentId().equals(parentId)).
                map(x -> getSysMenuListVo(parentId, x)).collect(Collectors.toList());
        //遍历父级菜单
        for (SysMenuListVo parentMenus : list) {
            List<SysMenuListVo> sysMenuListVos = buildMenus(menus, parentMenus.getId(), id, menuName);
            if (sysMenuListVos.size() > CommonConstants.ZERO) {
                //将子菜单加入到父级菜单下面
                parentMenus.setChildren(sysMenuListVos);
            }
        }
        return list;
    }

    private SysMenuListVo getSysMenuListVo(Integer parentId, SysMenu x) {
        SysMenuListVo sysMenuListVo = new SysMenuListVo();
        sysMenuListVo.setIcon(x.getIcon());
        sysMenuListVo.setTitle(x.getTitle());
        sysMenuListVo.setPath(x.getPath());
        sysMenuListVo.setPermissionCode(x.getPermissionCode());
        sysMenuListVo.setId(x.getId());
        sysMenuListVo.setParentId(parentId);
        return sysMenuListVo;
    }

}